
#ifndef CONTAINER_HPP
#define CONTAINER_HPP

#include <vector>

using IndexType = uint64_t;
template<typename ItemType>
class Container
{
private:
    std::vector<ItemType> _internal{};
    std::recursive_mutex mtx{};

public:
    Container() = default;
    Container(const Container& other) { _internal = other._internal; };
    Container& operator=(const Container& other)
    {
        _internal = other._internal;
        return *this;
    };
    bool add(ItemType item)
    {
        std::lock_guard<std::recursive_mutex> lock(mtx);
        _internal.push_back(item);
        return true;
    }

    bool insert(ItemType item, IndexType idx)
    {
        std::lock_guard<std::recursive_mutex> lock(mtx);
        _internal.insert(_internal.begin() + idx, item);
        return true;
    }

    bool move(ItemType item, IndexType toIdx)
    {
        std::lock_guard<std::recursive_mutex> lock(mtx);
        auto curr = index(item);
        if (curr < 0 || toIdx < 0 || toIdx > _internal.size() - 1)
        {
            return false;
        }

        if (curr == toIdx)
        {
            return true;
        }

        if (toIdx > curr)
        {
            toIdx -= 1;
        }

        removeAt(curr);
        insert(item, toIdx);

        return true;
    }

    IndexType index(ItemType item) const
    {
        auto it = std::find(_internal.begin(), _internal.end(), item);
        if (it == _internal.end())
        {
            return -1;
        }
        else
        {
            return (IndexType)(it - _internal.begin());
        }
    }

    bool remove(ItemType item)
    {
        removeAt(index(item));
        return true;
    }

    bool removeAt(IndexType idx)
    {
        std::lock_guard<std::recursive_mutex> lock(mtx);
        _internal.erase(_internal.begin() + idx);
        return true;
    }

    ItemType& get(IndexType idx) { return _internal.at(idx); }

    ItemType& operator[](IndexType idx) { return _internal[idx]; }

    std::vector<ItemType> items() { return _internal; };

    void clear() { _internal.clear(); };

    uint64_t size() { return _internal.size(); };
};

#endif //CONTAINER_HPP
